package com.wu.databasedemo.db;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.text.Annotation;
import android.text.TextUtils;

import com.wu.databasedemo.db.helper.AssociationColumn;
import com.wu.databasedemo.db.helper.AssociationType;
import com.wu.databasedemo.db.helper.NatrualKey;
import com.wu.databasedemo.db.helper.NotPersistent;
import com.wu.databasedemo.db.helper.Table;
import com.wu.databasedemo.db.helper.data.AssociationData;
import com.wu.databasedemo.db.helper.data.TableData;
import com.wu.databasedemo.db.util.LogUtil;
import com.wu.databasedemo.entity.Order;
import com.wu.databasedemo.entity.Product;

public class SQLiteManager {

	static final int VERSION = 5;

	public static SQLiteManager mManager;
	
	static Map<Class<?>, TableData> mEntityDBTables;
	
	static List<AssociationData> mRelationDBTables;

	static final String DATABASE_NAME = "test.db";

	static final Class<?>[] ENTITY_PERSISTENT = new Class<?>[] { Order.class, Product.class };

	private SQLiteManager() {
		super();
	}

	public static SQLiteManager getInstance() {
		if (mManager == null) {
			mManager = new SQLiteManager();
			initEntityDBTables();
		}
		return mManager;
	}

	static void initEntityDBTables() {
		if (mEntityDBTables == null) {
			mEntityDBTables = new HashMap<Class<?>, TableData>();
		}
		mEntityDBTables.clear();
		
		if (mRelationDBTables == null) {
			mRelationDBTables = new ArrayList<AssociationData>();
		}
		mRelationDBTables.clear();
		
		for (int i = 0; i < ENTITY_PERSISTENT.length; i++) {
			Class<?> cl = ENTITY_PERSISTENT[i];
			Field[] fields = cl.getDeclaredFields();
			boolean isTable = cl.isAnnotationPresent(Table.class);
			if (isTable && fields.length > 0) {
				String tableName = cl.getAnnotation(Table.class).TableName();
				if (tableName != null && tableName.length() > 0) {
					TableData data = new TableData();
					Map<String, Field> columns = new HashMap<String, Field>();
					String natrualKey = null;
					AssociationData asso = null;
					for (int j = 0; j < fields.length; j++) {
						Field field = fields[j];
						boolean notPersistent = field.isAnnotationPresent(NotPersistent.class);
						boolean isForeign = field.isAnnotationPresent(AssociationColumn.class);
						if (!notPersistent && !isForeign) {
							boolean isNatrualKey = field.isAnnotationPresent(NatrualKey.class);
							if (isNatrualKey) {
								natrualKey = getColumnFromAttribute(field);
							}
							columns.put(getColumnFromAttribute(field), field);
						}
						if (isForeign) {
							data.setHasForeign(true);
							Class<?> foreignClass = field.getAnnotation(AssociationColumn.class).foreignClass();
							if (foreignClass == AssociationColumn.ForeignDefault.class) {
								continue;
							}
							
							asso = new AssociationData();
							asso.setPrimaryField(field);
							asso.setPrimaryClass(cl);
							asso.setForeignClass(foreignClass);
							asso.setPrimaryTable(tableName);
							asso.setForeignTable(foreignClass.getAnnotation(Table.class).TableName());
							asso.setAssociationType(field.getAnnotation(AssociationColumn.class).associationType());
							asso.setRelationTable(getRelationTableName(asso));
							mRelationDBTables.add(asso);
							LogUtil.i("foreign key: " + asso);
						}
					}
					data.setTableName(tableName);
					if (TextUtils.isEmpty(natrualKey)) {
						natrualKey = Constant.PRIMARY_KEY;
					}
					data.setNatrualKey(natrualKey);
					data.setColumnFields(columns);
					mEntityDBTables.put(cl, data);
				}
			}
		}
	}
	
	public static String getNatrualValue(Object object) {
		TableData tableData = mEntityDBTables.get(object.getClass());
		Field natrualField = tableData.getColumnFields().get(tableData.getNatrualKey());
		natrualField.setAccessible(true);
		try {
			return natrualField.get(object).toString();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return "";
	}
	
	private static String getRelationTableName(AssociationData asso) {
		return ("relation_" + asso.getPrimaryTable() + "_" + asso.getForeignTable()).toUpperCase();
	}
	
	public static String getColumnFromAttribute(Field field) {
		if (field != null) {
			return field.getName().toUpperCase();
		}
		return "";
	}
	
	public static String getColumnFromAttribute(String attribute) {
		if (attribute != null) {
			return attribute.toUpperCase();
		}
		return "";
	}

	public static void beginTransaction() {
		SQLiteOperator.getInstance().getWritableDatabase().beginTransaction();
	}
	
	public static void endTransaction() {
		SQLiteOperator.getInstance().getWritableDatabase().endTransaction();
	}
	
}
